/* Copyright 2019 Eric Bavier.  Licensed under the GPLv3+ */

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <math.h>

int max_iter = 1000;
const char palette[] =
  {'.', ',', ':', ';', 'i', '+', '=', 'o', 'e', '*', 'l', 't', 'm', 'O', '&', '0', '8', '@', '#'};

int
main (int argc, char ** argv)
{
  int WIDTH, HEIGHT;
  double cx = -0.8, cy = 0.0;
  double zoom = 1.0;

  /* Initialize curses terminal handling */
  WINDOW * win = initscr();
  cbreak(); noecho();
  intrflush (stdscr, FALSE);
  keypad (stdscr, TRUE);
  getmaxyx(win, HEIGHT, WIDTH);
  
  while (1)
    {
      clear();
      for (int py = 0; py < HEIGHT; ++py)
	{
#pragma omp parallel for ordered schedule (dynamic)
	  for (int px = 0; px < WIDTH; ++px)
	    {
	      double x0 = (3.5/zoom) * ((double)(px - WIDTH/2) / WIDTH) + cx;
	      double y0 = (2.0/zoom) * ((double)(py - HEIGHT/2) / HEIGHT) +cy;
	      double x = 0, y=0;
	      int i = 0;
	      for (; x*x + y*y <= 4.0 && i < max_iter; ++i)
		{
		  double tmp = x*x - y*y + x0;
		  y = 2*x*y + y0;
		  x = tmp;
		}
#pragma omp ordered
	      {
		if (i == max_iter) addch (' ');
		else addch (palette[i % (sizeof(palette)-1)]);
	      }
	    }
	}
      move (HEIGHT-1,0);
      printw ("X: %.16f, Y: %.16f, zoom: %.10f, max: %d", cx, cy, zoom, max_iter);
      move (HEIGHT/2,WIDTH/2);
      refresh();

      /* See if the users wants to do anything else */
      int c = getch();
      switch (c){
      case KEY_DOWN: cy += 0.1 / zoom; break;
      case KEY_UP: cy -= 0.1 / zoom; break;
      case KEY_RIGHT: cx += 0.1 / zoom; break;
      case KEY_LEFT: cx -= 0.1 / zoom; break;
      case '+': zoom *= 1.1; max_iter *= 1.01; break;
      case '-': zoom /= 1.1; max_iter /= 1.01; break;
      case 'q': endwin(); exit(EXIT_SUCCESS);
      }
    }
}
